﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using Assist;
using Autodesk.Revit.Attributes;
using Autodesk.Revit.DB;
using Autodesk.Revit.Exceptions;
using Autodesk.Revit.UI;
using YArchitech.Revit;
using YArchitech.Revit.RevitExtension;
using HYView;

namespace YJKArch.WallModule
{
	[Regeneration(RegenerationOption.Manual)]
	[Transaction(TransactionMode.Manual)]
	public class CmdWallCornerSet : YJKCommandManual
	{
		[DllImport("user32.dll", EntryPoint = "SendMessageA")]
		public static extern int SendMessage(IntPtr hwnd, int wMsg, IntPtr wParam, IntPtr lParam);

		protected override Result YJKExcute(ExternalCommandData cmdData, ref string message, ElementSet elements)
		{
			CmdViewType types = (CmdViewType)11;
			if (SwitchView.SetUsableView(types, cmdData) != Autodesk.Revit.UI.Result.Succeeded)
			{
				return Autodesk.Revit.UI.Result.Failed;
			}
			if (CmdWallCornerSet._hWndRevit == null)
			{
				CmdWallCornerSet._hWndRevit = new WindowHandle(Process.GetCurrentProcess().MainWindowHandle);
			}
			Autodesk.Revit.DB.Document document = cmdData.Application.ActiveUIDocument.Document;
			DlgResetCorner dlgResetCorner = new DlgResetCorner();
			dlgResetCorner.Show(CmdWallCornerSet._hWndRevit);
			int wMsg = 7;
			CmdWallCornerSet.SendMessage(CmdWallCornerSet._hWndRevit.Handle, wMsg, IntPtr.Zero, IntPtr.Zero);
			for (;;)
			{
				Transaction transaction = new Transaction(this.m_doc, "wallcorner");
				transaction.Start();
				try
				{
					YJKArch.WallModule.WallFilter wallFilter = new YJKArch.WallModule.WallFilter();
					Reference reference = this.m_uiDoc.Selection.PickObject(Autodesk.Revit.UI.Selection.ObjectType.Element, wallFilter, "请选择第一道墙：");
					Wall wall = this.m_doc.GetElement(reference) as Wall;
					LocationCurve locationCurve = wall.Location as LocationCurve;
					Line line = locationCurve.Curve as Line;
					if (null == line)
					{
						transaction.RollBack();
						TaskDialog.Show("盈建科", "该命令仅支持直线墙倒角。");
						continue;
					}
					Reference reference2 = this.m_uiDoc.Selection.PickObject(Autodesk.Revit.UI.Selection.ObjectType.Element, wallFilter, "请选择第二道墙：");
					Wall wall2 = this.m_doc.GetElement(reference2) as Wall;
					Line line2 = (wall2.Location as LocationCurve).Curve as Line;
					if (null == line2)
					{
						transaction.RollBack();
						TaskDialog.Show("盈建科", "该命令仅支持直线墙倒角。");
						continue;
					}
					ElementArray elementArray = locationCurve.get_ElementsAtJoin(0);
					ElementArray elementArray2 = locationCurve.get_ElementsAtJoin(1);
					List<ElementId> list = new List<ElementId>();
					foreach (object obj in elementArray)
					{
						Element element = (Element)obj;
						list.Add(element.Id);
					}
					foreach (object obj2 in elementArray2)
					{
						Element element2 = (Element)obj2;
						list.Add(element2.Id);
					}
					XYZ xyz = this.Get2WallIntersectPt(wall, wall2);
					while ((xyz == null || wall.Id == wall2.Id) && (int)wall.WallType.Kind != 1 && (int)wall2.WallType.Kind != 1 && (int)wall.WallType.Kind != 2 && (int)wall2.WallType.Kind != 2)
					{
						MessageBox.Show("两段墙体没有相交，请重新选择第二道墙。", "盈建科提示");
						reference2 = this.m_uiDoc.Selection.PickObject(Autodesk.Revit.UI.Selection.ObjectType.Element, wallFilter, "请选择第二道墙：");
						wall2 = (this.m_doc.GetElement(reference2) as Wall);
						xyz = this.Get2WallIntersectPt(wall, wall2);
					}
					if ((int)wall.WallType.Kind == 1 || (int)wall2.WallType.Kind == 1)
					{
						MessageBox.Show("目前不支持幕墙的倒角操作！", "盈建科提示");
						transaction.RollBack();
						continue;
					}
					Result result;
					if (dlgResetCorner.m_bChamfer)
					{
						if (dlgResetCorner.Dist1 < 100.0 || dlgResetCorner.Dist2 < 100.0)
						{
							MessageBox.Show("倒角距离设置过小，最小应大于100mm，请检查！", "盈建科提示");
							transaction.RollBack();
							continue;
						}
						result = this.WallChamfer(reference, reference2, AssistFunc.mmToFeet(dlgResetCorner.Dist1), AssistFunc.mmToFeet(dlgResetCorner.Dist2), ref message);
					}
					else
					{
						if (dlgResetCorner.Radius < 100.0)
						{
							MessageBox.Show("倒角距离设置过小，最小应大于100mm，请检查！", "盈建科提示");
							transaction.RollBack();
							continue;
						}
						result = this.WallFillet(reference, reference2, AssistFunc.mmToFeet(dlgResetCorner.Radius), ref message);
					}
					if (result == null)
					{
						transaction.Commit();
						continue;
					}
					dlgResetCorner.Close();
					transaction.RollBack();
				}
				catch (Autodesk.Revit.Exceptions.OperationCanceledException)
				{
					transaction.RollBack();
					dlgResetCorner.Close();
					return Autodesk.Revit.UI.Result.Succeeded;
				}
				catch (Exception ex)
				{
					message = ex.Message;
					transaction.RollBack();
					return Autodesk.Revit.UI.Result.Failed;
				}
				break;
			}
			return Autodesk.Revit.UI.Result.Succeeded;
		}

		private Result WallChamfer(Reference ref1, Reference ref2, double dist1, double dist2, ref string message)
		{
			try
			{
				XYZ globalPoint = ref1.GlobalPoint;
				XYZ globalPoint2 = ref2.GlobalPoint;
				Wall wall = this.m_doc.GetElement(ref1) as Wall;
				Wall wall2 = this.m_doc.GetElement(ref2) as Wall;
				if (WallAssistFunc.GetWallCurveType(wall) != WallCurveType.eLineWall || WallAssistFunc.GetWallCurveType(wall2) != WallCurveType.eLineWall)
				{
					message = "选择的墙体不是直线墙！";
					return Autodesk.Revit.UI.Result.Failed;
				}
				XYZ xyz = this.Get2WallIntersectPt(wall, wall2);
				bool bClockwise = this.IsClockwise(wall, wall2, xyz);
				XYZ closestPointTo = CurveAssistFunc.GetClosestPointTo(this.m_uiApp, WallAssistFunc.GetWallCurve(wall), globalPoint, false);
				XYZ closestPointTo2 = CurveAssistFunc.GetClosestPointTo(this.m_uiApp, WallAssistFunc.GetWallCurve(wall2), globalPoint2, false);
				XYZ ptn = xyz + (closestPointTo - xyz).Normalize() * dist1;
				XYZ ptn2 = xyz + (closestPointTo2 - xyz).Normalize() * dist2;
				if (wall.WallType.Kind == null && wall2.WallType.Kind == null)
				{
					this.ResetOriginalWall(wall, ptn, wall2, ptn2, xyz);
				}
				WallDatum wallDatum = WallAssistFunc.GetWallDatum(this.m_doc, wall);
				WallAssistFunc.GetWallDatum(this.m_doc, wall2);
				Line lineWallBaseCurve = this.GetLineWallBaseCurve(ptn, ptn2, bClockwise);
				Wall wall3 = RevitVersionFuncs.NewWall(this.m_doc, lineWallBaseCurve, wallDatum.wallType, wallDatum.level, 15.0, 15.0, wall.Flipped, false);
				double num = wall.get_Parameter(BuiltInParameter.WALL_BASE_OFFSET).AsDouble();
				wall3.get_Parameter(BuiltInParameter.WALL_BASE_OFFSET).Set(num);
				ElementId elementId = wall.get_Parameter(BuiltInParameter.WALL_HEIGHT_TYPE).AsElementId();
				if (ElementId.InvalidElementId == elementId)
				{
					double num2 = wall.get_Parameter(BuiltInParameter.WALL_USER_HEIGHT_PARAM).AsDouble();
					wall3.get_Parameter(BuiltInParameter.WALL_USER_HEIGHT_PARAM).Set(num2);
				}
				else
				{
					double num3 = wall.get_Parameter(BuiltInParameter.WALL_TOP_OFFSET).AsDouble();
					wall3.get_Parameter(BuiltInParameter.WALL_HEIGHT_TYPE).Set(wallDatum.idTopLevel);
					wall3.get_Parameter(BuiltInParameter.WALL_TOP_OFFSET).Set(num3);
				}
			}
			catch (Exception ex)
			{
				message = ex.Message;
				return Autodesk.Revit.UI.Result.Failed;
			}
			return Autodesk.Revit.UI.Result.Succeeded;
		}

		private Result WallFillet(Reference ref1, Reference ref2, double radius, ref string message)
		{
			try
			{
				XYZ globalPoint = ref1.GlobalPoint;
				XYZ globalPoint2 = ref2.GlobalPoint;
				Wall wall = this.m_doc.GetElement(ref1) as Wall;
				Wall wall2 = this.m_doc.GetElement(ref2) as Wall;
				if (WallAssistFunc.GetWallCurveType(wall) != WallCurveType.eLineWall || WallAssistFunc.GetWallCurveType(wall2) != WallCurveType.eLineWall)
				{
					message = "选择的墙体不是直线墙！";
					return Autodesk.Revit.UI.Result.Failed;
				}
				XYZ xyz = this.Get2WallIntersectPt(wall, wall2);
				bool bClockwise = this.IsClockwise(wall, wall2, xyz);
				XYZ xyz2 = (CurveAssistFunc.GetClosestPointTo(this.m_uiApp, WallAssistFunc.GetWallCurve(wall), globalPoint, false) - xyz).Normalize();
				XYZ xyz3 = (CurveAssistFunc.GetClosestPointTo(this.m_uiApp, WallAssistFunc.GetWallCurve(wall2), globalPoint2, false) - xyz).Normalize();
				double num = xyz2.AngleTo(xyz3);
				double num2 = radius / Math.Tan(num / 2.0);
				XYZ xyz4 = xyz + xyz2 * num2;
				XYZ xyz5 = xyz + xyz3 * num2;
				if (wall.WallType.Kind == null && wall2.WallType.Kind == null)
				{
					this.ResetOriginalWall(wall, xyz4, wall2, xyz5, xyz);
				}
				WallDatum wallDatum = WallAssistFunc.GetWallDatum(this.m_doc, wall);
				WallAssistFunc.GetWallDatum(this.m_doc, wall2);
				xyz2 = (xyz4 - xyz).Normalize();
				xyz3 = (xyz5 - xyz).Normalize();
				XYZ xyz6 = ((xyz2 + xyz3) / 2.0).Normalize();
				double num3 = radius / Math.Sin(num / 2.0);
				XYZ xyz7 = xyz + xyz6 * num3;
				Arc arc = this.m_doc.CreatYJKArc(xyz7, radius, 0.0, Math.PI*2, XYZ.BasisX, XYZ.BasisY);
				Curve curve = YJKLineEx.YJKGetBound(xyz7, xyz);
				IntersectionResultArray intersectionResultArray = null;
				curve.Intersect(arc, out intersectionResultArray);
				if (intersectionResultArray == null)
				{
					return Autodesk.Revit.UI.Result.Failed;
				}
				if (intersectionResultArray.Size != 1)
				{
					return Autodesk.Revit.UI.Result.Failed;
				}
				XYZ xyzpoint = intersectionResultArray.get_Item(0).XYZPoint;
				Arc arcWallBaseCurve = this.GetArcWallBaseCurve(xyz4, xyz5, xyzpoint, bClockwise);
				Wall wall3 = RevitVersionFuncs.NewWall(this.m_doc, arcWallBaseCurve, wallDatum.wallType, wallDatum.level, 15.0, 15.0, wall.Flipped, false);
				double num4 = wall.get_Parameter(BuiltInParameter.WALL_BASE_OFFSET).AsDouble();
				wall3.get_Parameter(BuiltInParameter.WALL_BASE_OFFSET).Set(num4);
				ElementId elementId = wall.get_Parameter(BuiltInParameter.WALL_HEIGHT_TYPE).AsElementId();
				if (ElementId.InvalidElementId == elementId)
				{
					double num5 = wall.get_Parameter(BuiltInParameter.WALL_USER_HEIGHT_PARAM).AsDouble();
					wall3.get_Parameter(BuiltInParameter.WALL_USER_HEIGHT_PARAM).Set(num5);
				}
				else
				{
					double num6 = wall.get_Parameter(BuiltInParameter.WALL_TOP_OFFSET).AsDouble();
					wall3.get_Parameter(BuiltInParameter.WALL_HEIGHT_TYPE).Set(wallDatum.idTopLevel);
					wall3.get_Parameter(BuiltInParameter.WALL_TOP_OFFSET).Set(num6);
				}
			}
			catch (Autodesk.Revit.Exceptions.OperationCanceledException)
			{
				return Autodesk.Revit.UI.Result.Cancelled;
			}
			catch (Exception ex)
			{
				message = ex.Message;
				return Autodesk.Revit.UI.Result.Failed;
			}
			return Autodesk.Revit.UI.Result.Succeeded;
		}

		private XYZ Get2WallIntersectPt(Wall wall1, Wall wall2)
		{
			Line line = (wall1.Location as LocationCurve).Curve as Line;
			Line line2 = (wall2.Location as LocationCurve).Curve as Line;
			if (line == null || line2 == null)
			{
				return null;
			}
			XYZ result = null;
			IntersectionResultArray intersectionResultArray = null;
			Line line3 = line.Clone() as Line;
			Line line4 = line2.Clone() as Line;
			line3.MakeUnbound();
			line4.MakeUnbound();
			line3.Intersect(line4, out intersectionResultArray);
			if (intersectionResultArray != null && intersectionResultArray.Size == 1)
			{
				result = intersectionResultArray.get_Item(0).XYZPoint;
			}
			return result;
		}

		private void ResetOriginalWall(Wall wall1, XYZ ptn1, Wall wall2, XYZ ptn2, XYZ ptInt)
		{
			WallUtils.DisallowWallJoinAtEnd(wall1, 0);
			WallUtils.DisallowWallJoinAtEnd(wall1, 1);
			WallUtils.DisallowWallJoinAtEnd(wall2, 0);
			WallUtils.DisallowWallJoinAtEnd(wall2, 1);
			XYZ startPt = WallAssistFunc.GetStartPt(wall1);
			XYZ endPt = WallAssistFunc.GetEndPt(wall1);
			XYZ startPt2 = WallAssistFunc.GetStartPt(wall2);
			XYZ endPt2 = WallAssistFunc.GetEndPt(wall2);
			if (startPt.DistanceTo(ptInt) < endPt.DistanceTo(ptInt))
			{
				WallAssistFunc.ResetLineWall(this.m_app, this.m_doc, wall1, ptn1, endPt);
			}
			else
			{
				WallAssistFunc.ResetLineWall(this.m_app, this.m_doc, wall1, startPt, ptn1);
			}
			if (startPt2.DistanceTo(ptInt) < endPt2.DistanceTo(ptInt))
			{
				WallAssistFunc.ResetLineWall(this.m_app, this.m_doc, wall2, ptn2, endPt2);
			}
			else
			{
				WallAssistFunc.ResetLineWall(this.m_app, this.m_doc, wall2, startPt2, ptn2);
			}
			WallUtils.AllowWallJoinAtEnd(wall1, 0);
			WallUtils.AllowWallJoinAtEnd(wall1, 1);
			WallUtils.AllowWallJoinAtEnd(wall2, 0);
			WallUtils.AllowWallJoinAtEnd(wall2, 1);
		}

		private bool IsClockwise(Wall wall1, Wall wall2)
		{
			Curve wallCurve = WallAssistFunc.GetWallCurve(wall1);
			Curve wallCurve2 = WallAssistFunc.GetWallCurve(wall2);
			wallCurve.GetEndPoint(0);
			XYZ endPoint = wallCurve.GetEndPoint(1);
			XYZ endPoint2 = wallCurve2.GetEndPoint(0);
			wallCurve2.GetEndPoint(1);
			return endPoint.IsAlmostEqualTo(endPoint2);
		}

		private bool IsClockwise(Wall wall1, Wall wall2, XYZ ptIntersect)
		{
			Curve wallCurve = WallAssistFunc.GetWallCurve(wall1);
			Curve wallCurve2 = WallAssistFunc.GetWallCurve(wall2);
			XYZ endPoint = wallCurve.GetEndPoint(0);
			XYZ endPoint2 = wallCurve.GetEndPoint(1);
			XYZ endPoint3 = wallCurve2.GetEndPoint(0);
			XYZ endPoint4 = wallCurve2.GetEndPoint(1);
			return endPoint2.DistanceTo(ptIntersect) < endPoint.DistanceTo(ptIntersect) && endPoint3.DistanceTo(ptIntersect) < endPoint4.DistanceTo(ptIntersect);
		}

		private Line GetLineWallBaseCurve(XYZ ptn1, XYZ ptn2, bool bClockwise)
		{
			Line result;
			if (bClockwise)
			{
				result = YJKLineEx.YJKGetBound(ptn1, ptn2);
			}
			else
			{
				result = YJKLineEx.YJKGetBound(ptn2, ptn1);
			}
			return result;
		}

		private Arc GetArcWallBaseCurve(XYZ ptn1, XYZ ptn2, XYZ ptOnArc, bool bClockwise)
		{
			Arc result;
			if (bClockwise)
			{
				result = this.m_doc.CreatYJKArc(ptn1, ptn2, ptOnArc);
			}
			else
			{
				result = this.m_doc.CreatYJKArc(ptn2, ptn1, ptOnArc);
			}
			return result;
		}

		public static WindowHandle _hWndRevit;
	}
}
